package com.witdata.framework.service.message.impl;

import com.mybatisflex.core.query.QueryWrapper;
import com.witdata.mysql.base.service.SessionBaseService;
import com.witdata.common.domain.Status;
import com.witdata.common.domain.dto.MessageDto;
import com.witdata.common.domain.dto.SessionDto;
import com.witdata.mysql.domain.entity.TSession;
import com.witdata.common.domain.vo.UserVo;
import com.witdata.common.exception.GlobalException;
import com.witdata.common.domain.res.SessionResponse;
import com.witdata.common.mapper.SessionMapper;
import com.witdata.framework.service.message.MessageService;
import com.witdata.framework.service.message.SessionService;
import com.witdata.common.service.UserService;
import com.witdata.common.util.IdUtils;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@Service
@RequiredArgsConstructor
public class SessionServiceImpl implements SessionService {
    private final SessionBaseService sessionBaseService;
    private MessageService messageService;
    private final UserService userService;
    private final HttpServletRequest request;

    @Override
    public SessionDto createSession(SessionDto sessionDto) {
        TSession tSession = SessionMapper.INSTANCE.toTSessionBySessionDto(sessionDto);
        boolean exists = sessionBaseService.exists(new QueryWrapper()
                .eq("sender_id", sessionDto.getSenderId())
                .eq("receiver_id", sessionDto.getReceiverId()));
        if (exists) throw new GlobalException(Status.SESSIONISEXISTS);
        Long id = IdUtils.createId();
        tSession.setId(id);
        tSession.setCreated(LocalDateTime.now());
        boolean save = sessionBaseService.save(tSession);
        if (!save) throw new GlobalException(Status.CREATESESSIONERROR);
        sessionDto.setId(id);
        return sessionDto;
    }

    @Override
    public SessionDto getSession(Long senderId, Long receiverId) {
        TSession tSession = sessionBaseService.getOne(new QueryWrapper()
                .eq("sender_id", senderId)
                .eq("receiver_id", receiverId));
        if (!ObjectUtils.isEmpty(tSession)) return SessionMapper.INSTANCE.toSessionDto(tSession);
        tSession = sessionBaseService.getOne(new QueryWrapper()
                .eq("sender_id", receiverId)
                .eq("receiver_id", senderId));
        if (!ObjectUtils.isEmpty(tSession)) return SessionMapper.INSTANCE.toSessionDto(tSession);
        throw new GlobalException(Status.SESSIONNOTFOUND);
    }

    @Override
    public SessionDto getSession(Long sessionId) {
        TSession tSession = sessionBaseService.getOne(new QueryWrapper()
                .eq("id", sessionId));
        return SessionMapper.INSTANCE.toSessionDto(tSession);
    }

    @Override
    public Long getReceiverIdByUserId(Long sessionId, Long userId) {
        SessionDto sessionDto = getSession(sessionId);
        if (ObjectUtils.isEmpty(sessionDto)) throw new GlobalException(Status.SESSIONISEXISTS);
        if (sessionDto.getSenderId().equals(userId)) return sessionDto.getReceiverId();
        return sessionDto.getSenderId();
    }

    public List<SessionDto> getSessionListByUserId(Long userId) {
        List<TSession> tSessionList = new ArrayList<>();
        List<TSession> senderList = sessionBaseService.list(new QueryWrapper().eq("sender_id", userId));
        List<TSession> receiverList = sessionBaseService.list(new QueryWrapper().eq("receiver_id", userId));
        tSessionList.addAll(senderList);
        tSessionList.addAll(receiverList);
        return SessionMapper.INSTANCE.toSessionDtoList(tSessionList);
    }

    @Override
    public List<SessionResponse> getSessionList() {
        List<SessionResponse> sessionResponseList = new ArrayList<>();
        Long userId = IdUtils.getUserIdByRequest(request);
        List<SessionDto> sessionDtoList = getSessionListByUserId(userId);
        if (CollectionUtils.isEmpty(sessionDtoList)) return List.of();
        sessionDtoList.forEach(sessionDto -> {
            MessageDto latestMessage = messageService.getLatestMessage(sessionDto.getId());
            SessionResponse sessionResponse = SessionResponse.builder()
                    .sessionId(sessionDto.getId())
                    .latestMessage(latestMessage)
                    .build();
            UserVo receiver = userService.getUserVoById(sessionDto.getReceiverId());
            UserVo sender = userService.getUserVoById(sessionDto.getSenderId());
            if (sessionDto.getSenderId().equals(userId)) {
                sessionResponse.setReceiver(receiver);
                sessionResponse.setUnreadCounts(messageService.getUnreadCounts(sessionDto.getId(), sessionDto.getReceiverId()));
            } else {
                sessionResponse.setReceiver(sender);
                sessionResponse.setUnreadCounts(messageService.getUnreadCounts(sessionDto.getId(), sessionDto.getSenderId()));
            }
            sessionResponseList.add(sessionResponse);
        });
        return sessionResponseList;
    }

    @Lazy
    @Autowired
    public void setMessageService(MessageService messageService) {
        this.messageService = messageService;
    }
}
